package org.biubiu0002.baiblog.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.dubbo.config.annotation.DubboReference;
import org.biubiu0002.baiblog.common.exception.BaiBlogException;
import org.biubiu0002.baiblog.common.exception.BizCodeEnumException;
import org.biubiu0002.baiblog.core.dao.GroupUserDao;
import org.biubiu0002.baiblog.core.model.dto.TokenUserDto;
import org.biubiu0002.baiblog.core.model.entity.GroupUserEntity;
import org.biubiu0002.baiblog.core.model.entity.MessageEntity;
import org.biubiu0002.baiblog.core.model.entity.SysUserEntity;
import org.biubiu0002.baiblog.core.model.vo.UserInfoVo;
import org.biubiu0002.baiblog.core.model.vo.req.GroupUserInviteReqVo;
import org.biubiu0002.baiblog.core.service.ConversationService;
import org.biubiu0002.baiblog.core.service.GroupUserService;
import org.biubiu0002.baiblog.core.service.MessageService;
import org.biubiu0002.baiblog.core.service.SysUserService;
import org.biubiu0002.baiblog.core.utils.SecurityUtils;
import org.biubiu0002.baiblog.im.api.NotifyApiService;
import org.biubiu0002.baiblog.im.constants.MessageConstants;
import org.biubiu0002.baiblog.im.dto.conversation.ConversationUserInfoDto;
import org.biubiu0002.baiblog.im.dto.message.notification.GroupUserJoinedNotification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: biubiu0002
 * @Date: 2022/12/8 14:10
 **/
@Service
public class GroupUserServiceImpl extends ServiceImpl<GroupUserDao, GroupUserEntity> implements GroupUserService {

    @Resource
    private SysUserService sysUserService;

    @Resource
    private GroupUserDao groupUserDao;

    @Resource
    private ConversationService conversationService;

    @Resource
    private MessageService messageService;

    @DubboReference
    private NotifyApiService notifyApiService;

    @Override
    public List<UserInfoVo> getGroupUserInfo(String uid) {
        List<String> userUidList = this.getGroupUsersFromDB(uid);
        Map<String, UserInfoVo> userInfoMap = sysUserService.getUserInfoMap(userUidList);
        return new ArrayList<>(userInfoMap.values());
    }

    @Override
    public List<String> getGroupUserUidList(String groupUid) {
        List<String> groupUsersFromDB = this.getGroupUsersFromDB(groupUid);
        if(CollectionUtils.isEmpty(groupUsersFromDB)){
           return Collections.emptyList();
        }
        return groupUsersFromDB;
    }

    private List<String> getGroupUsersFromDB(String groupUid){
        List<GroupUserEntity> list = this.list(new QueryWrapper<GroupUserEntity>()
                .eq("group_id", groupUid));
        if(CollectionUtils.isEmpty(list)){
           return Collections.emptyList();
        }
        return list.stream().map(GroupUserEntity::getUserId).collect(Collectors.toList());
    }


    @Override
    @Transactional(rollbackFor = BaiBlogException.class)
    public void inviteUser(GroupUserInviteReqVo groupUserInviteReqVo) {
        TokenUserDto user = SecurityUtils.getUser();
        String groupUid = groupUserInviteReqVo.getGroupUid();
        List<String> uidList = groupUserInviteReqVo.getUidList();
        String userUid = user.getUserUid();
        //检查邀请人是否在群聊中
        checkUserInGroup(groupUid, userUid,uidList);
        //检查这些用户是否存在
        Map<String, SysUserEntity> uidUserMap = checkUsersExisted(uidList);
        List<String> invitedUidList = new ArrayList<>(uidUserMap.keySet());
        //群组用户关系落库
        List<GroupUserEntity> groupUserEntities = uidList.stream().map(item -> {
            GroupUserEntity groupUserEntity = new GroupUserEntity();
            groupUserEntity.setUserId(item);
            groupUserEntity.setGroupId(groupUid);
            return groupUserEntity;
        }).collect(Collectors.toList());
        this.saveBatch(groupUserEntities);
        //组装入群消息
        GroupUserJoinedNotification groupUserJoinedNotification = new GroupUserJoinedNotification();
        groupUserJoinedNotification.setGroupUid(groupUid);
        groupUserJoinedNotification.setInviteUid(userUid);
        groupUserJoinedNotification.setInvitedUidList(invitedUidList);
        String content = JSON.toJSONString(groupUserJoinedNotification);
        //入群消息(系统消息)落库
        MessageEntity messageEntity = new MessageEntity();
        messageEntity.setMsgId(IdWorker.getId());
        messageEntity.setMsgType(MessageConstants.MessageCommandType.GROUP_JOINED_MESSAGE);
        messageEntity.setFromUid(userUid);
        messageEntity.setToUid(groupUid);
        messageEntity.setMsgContent(content);
        messageEntity.setSendTime(new Date());
        messageService.save(messageEntity);
        List<String> groupUserUidList = this.getGroupUserUidList(groupUid);
        //入群消息修改群成员会话列表,未读消息
        conversationService.invitedToGroupConversation(groupUid,groupUserUidList,content);
        //入群消息(系统消息)在线推送到群聊 RPC
        List<ConversationUserInfoDto> conversationUserInfoDtoList = uidUserMap.values().stream().map(item -> {
            ConversationUserInfoDto conversationUserInfoDto = new ConversationUserInfoDto();
            conversationUserInfoDto.setUid(item.getResourceId());
            conversationUserInfoDto.setAvatar(item.getAvatar());
            conversationUserInfoDto.setNickname(item.getNickname());
            return conversationUserInfoDto;
        }).collect(Collectors.toList());
        groupUserJoinedNotification.setConversationUserInfoDtoList(conversationUserInfoDtoList);
        content = JSON.toJSONString(groupUserJoinedNotification);
        notifyApiService.notifyGroup(MessageConstants.MessageCommandType.GROUP_JOINED_MESSAGE,groupUserUidList,groupUid,content);


    }

    private Map<String, SysUserEntity> checkUsersExisted(List<String> uidList) {
        List<SysUserEntity> usersByUidList = sysUserService.getUsersByUidList(uidList);
        Map<String, SysUserEntity> map = usersByUidList.stream().collect(Collectors.toMap(SysUserEntity::getResourceId, e -> e, (o1, o2) -> o2));
        Set<String> dbUidSet = map.keySet();
        for(String uid: uidList){
            if(!dbUidSet.contains(uid)){
                throw new BaiBlogException(BizCodeEnumException.USER_NOT_EXIST_EXCEPTION);
            }
        }
        return map;
    }

    private void checkUserInGroup(String groupUid, String userUid ,List<String> invitedUidList) {
        List<String> groupUsersFromDB = this.getGroupUsersFromDB(groupUid);
        Set<String> set = new HashSet<>(groupUsersFromDB);
        if(!set.contains(userUid)){
            throw new BaiBlogException(BizCodeEnumException.NOT_IN_GROUP_EXCEPTION);
        }
        for (String uid : invitedUidList) {
            if(set.contains(uid)){
                throw new BaiBlogException(BizCodeEnumException.HAD_IN_GROUP_EXCEPTION,uid+"已在群聊中，邀请失败");
            }
        }
    }
}
